﻿using MCUPackage;
using MCUPackage.Utils;
using SxPackages.STC8.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SxPackages.STC8.DesignEditor;
using System.Windows.Forms;

namespace SxPackages.STC8
{
	[Serializable]
	public class STC8HUSOP20 : MCUOptions
	{
		/// <summary>
		/// 芯片型号, 要保证与工具导出中的型号命名一致
		/// </summary>
		internal const string MODEL = "STC8HUSOP20";

		/// <summary>
		/// 系统设置
		/// </summary>
		internal SysOptions mSystem { get; private set; }
		/// <summary>
		/// ADC配置
		/// </summary>
		internal ADCOptions mADC { get; private set; }
		/// <summary>
		/// 比较器配置
		/// </summary>
		internal CMPOptions mCMP { get; private set; }
		/// <summary>
		/// PWM集合
		/// </summary>
		internal AllPWMOptions mPWMs { get; private set; }
		/// <summary>
		/// 定时器集合
		/// </summary>
		internal AllTmrOptions mTmrs { get; private set; }
		/// <summary>
		/// 实时时钟设置
		/// </summary>
		internal RTCOptions mRTC { get; private set; }
		/// <summary>
		/// 串口集合
		/// </summary>
		internal AllUartOptions mUarts { get; private set; }
		/// <summary>
		/// SPI接口集合
		/// </summary>
		internal AllSPIOptions mSPIs { get; private set; }
		/// <summary>
		/// IIC接口集合
		/// </summary>
		internal AllIICOptions mIICs { get; private set; }
		/// <summary>
		/// USB配置
		/// </summary>
		internal USBOptions mUSB { get; private set; }
		/// <summary>
		/// 数学库配置
		/// </summary>
		internal MathOptions mMath { get; private set; }
		/// <summary>
		/// ZnFAT配置
		/// </summary>
		internal ZnFatOptions mZnFat { get; private set; }
		/// <summary>
		/// 工程配置, 如无特殊配置可以不需要重写, 但必须要实例化
		/// </summary>
		internal STC8ProjectOptions mProject { get; private set; }

		public override Object SYSTEM => mSystem;
		public override Object ADC => mADC;
		public override Object CMP => mCMP;
		public override Object PWMs => mPWMs;
		public override Object Tmrs => mTmrs;
		public override Object RTC => mRTC;
		public override Object Uarts => mUarts;
		public override Object SPIs => mSPIs;
		public override Object IICs => mIICs;
		public override Object LCM => null;
		public override Object USB => mUSB;
		public override Object IIS => null;
		public override Object Math => mMath;
		public override Object ZnFat => mZnFat;
		public override Object FreeRTOS => null;
		public override ProjectOptions Project => mProject;

		public override String Model => MODEL;

		public STC8HUSOP20(MCUAttribute aMCU, String aTemplateRoot) : base(aMCU, aTemplateRoot)
		{
			this.TemplatePath = Path.Combine(mTemplateRoot, "STC8HU");
			PinsConvertor.PinNames = this.PinNames;

			mSystem = new SysOptions(this);
			mADC = new ADCOptions(this);
			mCMP = new CMPOptions(this);
			mPWMs = new AllPWMOptions(this);
			mTmrs = new AllTmrOptions(this);
			mRTC = new RTCOptions(this);
			mUarts = new AllUartOptions(this);
			mSPIs = new AllSPIOptions(this);
			mIICs = new AllIICOptions(this);
			mUSB = new USBOptions(this);
			mMath = new MathOptions(this);
			mZnFat = new ZnFatOptions(this);
			mProject = new STC8ProjectOptions(this);
		}

		/// <summary>
		/// 根据模板创建文件
		/// </summary>
		/// <param name="aType"></param>
		/// <param name="aDstPath"></param>
		/// <param name="aFile"></param>
		/// <param name="aAppend"></param>
		/// <param name="aPairs"></param>
		/// <param name="aTitle"></param>
		/// <returns></returns>
		internal bool CreateByTemplate(PathTypes aType, string aDstPath, string aFile, bool aAppend, Dictionary<string, string> aPairs, string aTitle = null)
		{
			string template = Path.Combine(aType.ToFilePath(TemplatePath, aFile));
			string dst = Path.Combine(aType.ToFilePath(aDstPath, aFile));

			if (CreateByTemplate(template, dst, aPairs, aTitle))
			{
				if (aAppend)
				{
					PrjTemplate.Append(aType, aFile);
				}
				return true;
			}

			return false;
		}

		public override String GetFreq()
		{
			return this.mSystem.Freq;
		}

		/// <summary>
		/// 获取include文件
		/// </summary>
		/// <returns></returns>
		private string GetIncludes()
		{
			StringBuilder tmpSb = new StringBuilder();
			tmpSb.AppendLine("#include \"Config.h\"");
			tmpSb.AppendLine("#include \"STC8G_H_GPIO.h\"");
			tmpSb.AppendLine("#include \"STC8G_H_Switch.h\"");
			tmpSb.AppendLine("#include \"STC8G_H_NVIC.h\"");
			tmpSb.AppendLine("#include \"STC8G_H_Timer.h\"");

			if (this.mSystem.EnableWDG)
			{
				tmpSb.AppendLine("#include \"STC8G_H_WDT.h\"");
			}
			if (this.mADC.Enable)
			{
				tmpSb.AppendLine("#include \"STC8G_H_ADC.h\"");
			}
			if (this.mCMP.Enable)
			{
				tmpSb.AppendLine("#include \"STC8G_H_Compare.h\"");
			}
			if (this.mPWMs.HasEnabled())
			{
				tmpSb.AppendLine("#include \"STC8H_PWM.h\"");
			}
			if (this.mRTC.Enable)
			{
				tmpSb.AppendLine("#include \"STC8H_RTC.h\"");
			}
			if (this.mUarts.HasEnabled())
			{
				tmpSb.AppendLine("#include \"STC8G_H_UART.h\"");
			}
			if (this.mSPIs.SPI.Enable)
			{
				tmpSb.AppendLine("#include \"STC8G_H_SPI.h\"");
			}
			if (this.mSPIs.Soft.Enable)
			{
				tmpSb.AppendLine("#include \"STC8H_Soft_SPI.h\"");
			}
			if (this.mIICs.IIC.Enable)
			{
				tmpSb.AppendLine("#include \"STC8G_H_I2C.h\"");
			}
			if (this.mIICs.Soft.Enable)
			{
				tmpSb.AppendLine("#include \"STC8G_H_Soft_I2C.h\"");
			}
			if (this.mUSB.Enable)
			{
				tmpSb.AppendLine("#include \"stc32_stc8_usb.h\"");
			}

			return tmpSb.ToString();
		}

		/// <summary>
		/// 是否有GPIO开启了中断
		/// </summary>
		/// <returns></returns>
		private bool HasGPIOEnableTI()
		{
			foreach (var io in this.GPIOs)
			{
				if (io.Interrupt != GPIO_TI.None)
				{
					return true;
				}
			}

			return false;
		}

		/// <summary>
		/// 获取GPIO配置函数
		/// </summary>
		/// <returns></returns>
		private string[] GetGPIOConfig()
		{
			Dictionary<string, List<string>> lst = new Dictionary<string, List<string>>();
			// 选出启用的普通IO口
			foreach (var gpio in this.GPIOs)
			{
				if (gpio.Mode != GPIOMode.None && this.GetPinPurpose(gpio.Name) <= PinPurpose.GPIO)
				{
					gpio.ToSTC8Dictionary(lst);
				}
			}

			if (lst.Count < 1)
			{
				// 无需配置
				return null;
			}

			string name = "GPIO_Config";
			StringBuilder tmpSb = new StringBuilder();
			tmpSb.Append(TemplateHelper.GetFunctionCommit("GPIO口初始化"));
			tmpSb.AppendLine($"PRIVATE void {name}(void)").AppendLine("{");
			tmpSb.Append(GPIOOptions.GetGPIOConfigs(lst));
			tmpSb.AppendLine("}");
			return new string[] { tmpSb.ToString(), $"{name}();" };
		}

		/// <summary>
		/// 系统设置中打印口设置有效性检测
		/// </summary>
		/// <returns></returns>
		private bool PrintPortValid()
		{
			var port = mSystem.Port;
			if (port == PrintfPort.不设置)
			{
				return true;
			}
			if (port == PrintfPort.USB_HID)
			{
				if (mUSB.Enable)
				{
					return true;
				}
				else
				{
					GuiUtils.MsgBox("printf默认输出需要开启USB功能.");
					return false;
				}
			}
			if (mUarts.All[(int)port - 1].Enable)
			{
				return true;
			}
			else
			{
				GuiUtils.MsgBox($"printf默认输出需要开启{port}.");
				return false;
			}
		}

		/// <summary>
		/// 生成工程前的有效性检测
		/// </summary>
		/// <returns>返回无效的设置项, MAX说明通过</returns>
		public override OptionsTypes PreGenerate()
		{
			if (string.IsNullOrEmpty(Project.Name))
			{
				GuiUtils.MsgBox("请在工程设置中填写项目名称...");
				return OptionsTypes.Project;
			}
			if (!PrintPortValid())
			{
				return OptionsTypes.System;
			}
			if (mADC.Enable && string.IsNullOrEmpty(mADC.UsePins.Trim()))
			{
				if (GuiUtils.MsgBox("ADC通道引脚未设置, 是否进行设置?") == DialogResult.OK)
				{
					return OptionsTypes.ADC;
				}
			}
			if (mSPIs.Soft.Enable && !mSPIs.Soft.PinsValid())
			{
				if (GuiUtils.MsgBox("模拟SPI功能的引脚未设置完全, 是否进行设置?") == DialogResult.OK)
				{
					return OptionsTypes.SPI;
				}
			}
			if (mIICs.Soft.Enable && !mIICs.Soft.PinsValid())
			{
				GuiUtils.MsgBox("模拟I2C功能的引脚未设置完全!");
				return OptionsTypes.IIC;
			}

			return OptionsTypes.TYPE_MAX;
		}

		/// <summary>
		/// 创建芯片初始化文档
		/// </summary>
		/// <returns></returns>
		private bool Generate(string aPath)
		{
			string file = "ChipInit.c";

			StringBuilder tmpSb = new StringBuilder();
			// 函数拼接
			StringBuilder funcSb = new StringBuilder();
			// 初始化函数拼接
			StringBuilder initSb = new StringBuilder();
			// 变量声明拼接
			StringBuilder varSb = new StringBuilder();
			List<string[]> lst = new List<string[]>();

			tmpSb.AppendLine(GetIncludes());

			initSb.Append(TemplateHelper.GetFunctionCommit("芯片模块初始化"));
			initSb.AppendLine("void Chip_Init(void)").AppendLine("{");
			initSb.AppendLine("	EAXSFR();		// 扩展SFR(XFR)访问使能");

			string[] strs = GetGPIOConfig();
			if (strs != null)
			{
				funcSb.AppendLine(strs[0]);
				initSb.AppendLine($"\t{strs[1]}");
			}

			this.mUarts.AppendConfig(lst);
			this.mSPIs.SPI.AppendConfig(lst);
			this.mSPIs.Soft.AppendConfig(aPath, lst);
			this.mIICs.IIC.AppendConfig(lst);
			this.mIICs.Soft.AppendConfig(aPath, lst);
			this.mADC.AppendConfig(lst);
			this.mCMP.AppendConfig(lst);
			this.mPWMs.AppendConfig(lst);
			this.mRTC.AppendConfig(lst);
			this.mTmrs.AppendConfig(lst);
			this.mUSB.AppendConfig(lst);
			this.mSystem.AppendConfig(lst);

			foreach (var item in lst)
			{
				funcSb.AppendLine(item[0]);
				initSb.AppendLine($"\t{item[1]}");
				if (item.Length > 2 && !string.IsNullOrEmpty(item[2]))
				{
					varSb.AppendLine(item[2]);
				}
			}

			initSb.AppendLine().AppendLine("\tEA = 1;");
			initSb.AppendLine("}");

			string str = varSb.ToString();
			if (!string.IsNullOrEmpty(str))
			{
				tmpSb.AppendLine(varSb.ToString());
			}
			tmpSb.Append(funcSb.ToString());
			tmpSb.Append(initSb.ToString());

			PrjTemplate.Append(PathTypes.Src, file);
			CreateFile(PathTypes.Src.ToFilePath(aPath, file), tmpSb.ToString(), "芯片各模块初始化接口实现");

			return true;
		}

		/// <summary>
		/// 创建.gitignore文件
		/// </summary>
		/// <param name="aPath"></param>
		/// <param name="aProjectName"></param>
		/// <returns></returns>
		private bool CreateGitIgnore(string aPath)
		{
			string file = ".gitignore";
			string template = Path.Combine(TemplatePath, file);
			string path = Path.Combine(aPath, file);

			var pairs = TemplateHelper.CreatePairs();
			pairs["ProjectName"] = Project.Name;

			return CreateByTemplate(template, path, pairs, null);
		}

		/// <summary>
		/// 创建ReadMe.txt文件
		/// </summary>
		/// <param name="aPath"></param>
		/// <param name="aOpt"></param>
		/// <returns></returns>
		private bool CreateReadMe(string aPath)
		{
			string file = "ReadMe.txt";

			PrjTemplate.Append(PathTypes.Doc, file);
			return CreateFile(PathTypes.Doc.ToFilePath(aPath, file), string.Empty, "项目说明文档");
		}

		/// <summary>
		/// 复制官方库文件
		/// </summary>
		/// <param name="aOptions"></param>
		/// <param name="aPath"></param>
		private void CopyLibs(string aPath)
		{
			List<string> incFiles = new List<string>();
			List<string> srcFiles = new List<string>();
			List<string> libFiles = new List<string>();

			// 系统必须包含的头文件
			incFiles.Add("STC8H.h");
			incFiles.Add("Type_def.h");
			incFiles.Add("STC8G_H_GPIO.h");
			incFiles.Add("STC8G_H_NVIC.h");
			incFiles.Add("STC8G_H_Delay.h");
			incFiles.Add("STC8G_H_Switch.h");
			incFiles.Add("STC8G_H_Timer.h");
			// 必须包含的源文件
			srcFiles.Add("STC8G_H_GPIO.c");
			srcFiles.Add("STC8G_H_NVIC.c");
			srcFiles.Add("STC8G_H_Delay.c");
			srcFiles.Add("STC8G_H_Timer.c");
			srcFiles.Add("STC8G_H_Timer_Isr.c");

			// 根据开启的功能进行文件复制
			bool flag = Project.AllLib;

			// 看门狗
			if (flag || mSystem.EnableWDG)
			{
				incFiles.Add("STC8G_H_WDT.h");
				srcFiles.Add("STC8G_H_WDT.c");
			}

			// EEPROM
			if (flag || mSystem.EnableFlash)
			{
				incFiles.Add("STC8G_H_EEPROM.h");
				srcFiles.Add("STC8G_H_EEPROM.c");
			}

			// ADC
			if (flag || mADC.Enable)
			{
				incFiles.Add("STC8G_H_ADC.h");
				srcFiles.Add("STC8G_H_ADC.c");
				if (flag || mADC.EnableTI)
				{
					srcFiles.Add("STC8G_H_ADC_Isr.c");
				}
			}

			// CMP
			if (flag || mCMP.Enable)
			{
				incFiles.Add("STC8G_H_Compare.h");
				srcFiles.Add("STC8G_H_Compare.c");
				if (flag || (mCMP.EnableNTI || mCMP.EnablePTI))
				{
					srcFiles.Add("STC8G_H_Compare_Isr.c");
				}
			}

			// PWM
			if (flag || mPWMs.HasEnabled())
			{
				incFiles.Add("STC8H_PWM.h");
				srcFiles.Add("STC8H_PWM.c");
				srcFiles.Add("STC8H_PWM_Isr.c");
			}

			// RTC
			if (flag || mRTC.Enable)
			{
				incFiles.Add("STC8H_RTC.h");
				srcFiles.Add("STC8H_RTC.c");
				if (flag || mRTC.HasInterrupt())
				{
					srcFiles.Add("STC8H_RTC_Isr.c");
				}
			}

			// UART
			if (flag || mUarts.HasEnabled())
			{
				srcFiles.Add("STC8G_H_UART.c");
				srcFiles.Add("STC8G_H_UART_Isr.c");
			}

			// SPI
			if (flag || mSPIs.SPI.Enable)
			{
				incFiles.Add("STC8G_H_SPI.h");
				srcFiles.Add("STC8G_H_SPI.c");
				if (flag || mSPIs.SPI.EnableTI)
				{
					srcFiles.Add("STC8G_H_SPI_Isr.c");
				}
			}
			if (flag || mSPIs.Soft.Enable)
			{
				srcFiles.Add("STC8H_Soft_SPI.c");
				if (!mSPIs.Soft.Enable)
				{
					mSPIs.Soft.CreateLibFiles(aPath);
				}
			}

			// IIC
			if (flag || mIICs.IIC.Enable)
			{
				incFiles.Add("STC8G_H_I2C.h");
				srcFiles.Add("STC8G_H_I2C.c");
				if (flag || mIICs.IIC.EnableTI)
				{
					srcFiles.Add("STC8G_H_I2C_Isr.c");
				}
			}
			if (flag || mIICs.Soft.Enable)
			{
				incFiles.Add("STC8G_H_Soft_I2C.h");
				if (!mIICs.Soft.Enable)
				{
					mIICs.Soft.CreateLibFiles(aPath);
				}
			}

			if (flag || HasGPIOEnableTI())
			{
				srcFiles.Add("STC8G_H_GPIO_Isr.c");
			}

			// USB
			if (mUSB.Enable)
			{
				if (mUSB.Type == USBTypes.CDC协议)
				{
					libFiles.Add("stc_usb_cdc_8h_xdata_interrupt.LIB");
				}
				else if (mUSB.Type == USBTypes.HID协议)
				{
					libFiles.Add("stc_usb_hid_8h_xdata.LIB");
				}
			}

			// 数学库
			if (flag || mMath.EnableMDU)
			{
				libFiles.Add("STC8_MDU32C.LIB");
			}

			foreach (var file in incFiles)
			{
				File.Copy(PathTypes.Drivers_STC_Inc.ToFilePath(TemplatePath, file), PathTypes.Drivers_STC_Inc.ToFilePath(aPath, file), true);
			}
			foreach (var file in srcFiles)
			{
				PrjTemplate.Append(PathTypes.Drivers_STC_Src, file);
				File.Copy(PathTypes.Drivers_STC_Src.ToFilePath(TemplatePath, file), PathTypes.Drivers_STC_Src.ToFilePath(aPath, file), true);
			}
			foreach (var file in libFiles)
			{
				PrjTemplate.Append(PathTypes.Drivers_STC_Libs, file);
				File.Copy(PathTypes.Drivers_STC_Libs.ToFilePath(TemplatePath, file), PathTypes.Drivers_STC_Libs.ToFilePath(aPath, file), true);
			}
		}

		/// <summary>
		/// USB HID启用模板
		/// </summary>
		private const string USB_HID_TEMPLATE =
@"// 启用USB HID时必须定义下面两个变量
char *USER_DEVICEDESC = SX_NULL;
char *USER_PRODUCTDESC = SX_NULL;
";

		/// <summary>
		/// 创建项目配置文档
		/// </summary>
		/// <param name="aPath"></param>
		private bool CreateConfig(string aPath)
		{
			string file = "ProjectConfig.c";
			var pairs = TemplateHelper.CreatePairs();
			pairs["ProjectName"] = Project.Name;
			pairs["Org"] = Project.Org;
			pairs["UsbHID"] = (mUSB.Enable && mUSB.Type == USBTypes.HID协议) ? USB_HID_TEMPLATE : "";
			CreateByTemplate(PathTypes.Src, aPath, file, true, pairs, "项目配置");

			file = "ProjectConfig.h";
			CreateByTemplate(PathTypes.Inc, aPath, file, true, null, "项目配置接口声明");
			file = "ModuleConfig.h";
			PrjTemplate.Append(PathTypes.Inc, file);
			CreateFile(PathTypes.Inc.ToFilePath(aPath, file), string.Empty, "功能模块配置声明, 使能模块宏定义可在本文件中定义");

			return true;
		}

		/// <summary>
		/// 添加启动汇编文件
		/// </summary>
		/// <param name="aPath"></param>
		/// <returns></returns>
		private bool AppendStartup(string aPath)
		{
			string file = "STARTUP.A51";

			PrjTemplate.Append(PathTypes.Src, file);
			File.Copy(PathTypes.Src.ToFilePath(TemplatePath, file), PathTypes.Src.ToFilePath(aPath, file), true);
			return true;
		}

		/// <summary>
		/// 创建程序入口文件
		/// </summary>
		/// <param name="aPath"></param>
		private bool CreateMain(string aPath)
		{
			string file = "Main.c";
			var pairs = TemplateHelper.CreatePairs();

			StringBuilder tmpSb = new StringBuilder();
			if (mZnFat.Enable)
			{
				tmpSb.AppendLine("#include \"znFAT.h\"");
			}
			pairs["include"] = tmpSb.ToString();

			return CreateByTemplate(PathTypes.Src, aPath, file, true, pairs, "程序入口文件");
		}

		/// <summary>
		/// 创建工程
		/// </summary>
		/// <param name="aOptions"></param>
		/// <param name="aPath"></param>
		/// <returns></returns>
		public override bool CreateProject(string aPath)
		{
			PrjTemplate.Init();
			// 创建工程目录
			for (PathTypes type = PathTypes.Assets; type <= PathTypes.MDK; type++)
			{
				string folder = type.ToDescription();
				Directory.CreateDirectory(Path.Combine(aPath, folder));
			}

			// 创建.gitignore文件
			CreateGitIgnore(aPath);
			// ReadMe文档
			CreateReadMe(aPath);

			// 复制库文件
			CopyLibs(aPath);

			// 创建系统文件
			mSystem.Cenerate(aPath);
			// 创建项目配置文件
			if (!CreateConfig(aPath))
			{
				return false;
			}

			// ZnFat配置
			mZnFat.Generate(aPath);

			// 创建芯片初始化文件
			Generate(aPath);

			// 创建程序入口文件
			CreateMain(aPath);
			AppendStartup(aPath);

			PrjTemplate.Create(aPath, this);

			return true;
		}
	}
}
